package p04_bean后处理器;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.context.support.GenericApplicationContext;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

/**
 * bean后处理器负责对bean生命周期的各个阶段注解进行解析
 * AutowiredAnnotationBeanPostProcessor  --->  @Autowired,@Value
 * CommonAnnotationBeanPostProcessor   --->   @Resource,@PostConstruct,@PreDestroy
 */
public class _1_常见bean后处理器演示 {
    public static void main(String[] args) {
        /**
         * 这里用GenericApplicationContext来做测试，这是一个干净的容器
         * 这个容器中只要加了后处理器,调用refresh()方法就会自动运行beanFactory后处理器、bean后处理器和初始化单例，并且对bean后处理器进行了排序
         * DefaultListableBeanFactory相对而来太原生了
         */
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("bean1", Bean1.class);
        context.registerBean("bean2", Bean2.class);
        context.registerBean("bean3", Bean3.class);

        /**
         * 下面演示依次添加bean后处理器
         * 添加一个bean后处理器，bean的生命周期就会丰富一点
         */
        //加了这行，就能通过@Value进行值注入(与AutowiredAnnotationBeanPostProcessor配合)
        context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        //解析@Autowird,@Value的bean后处理器，该bean后处理器的类名翻译:Autowired注解的bean后处理器
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        //@Resource,@PostConstruct,@PreDestroy注解解析,该bean后处理器的类名翻译:公共注解的bean后处理器
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        //springboot的后处理器，解析@ConfigurationProperties，初始化前执行
        ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());

        /**
         * 上面把三个bean后处理器注册成bean，但对spring容器来说，此时他们就是普通的bean，要是他们能够作为bean后处理器生效，必须运行他们
         * 这行代码的功能是:执行beanFactory后处理器，添加bean后处理器，初始化单例
         */
        context.refresh();

        Bean3 bean3 = context.getBean("bean3", Bean3.class);
        //通过观察打印了哪些信息，就能判断哪些注解生效了
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println("====>" + context.getBean(name));
        }

        context.close();
    }

    @Slf4j
    static class Bean1 {
        public Bean1() {
            log.warn("创建了bean1");
        }

        @Autowired
        public void setBean2(Bean2 bean2) {
            System.out.println("bean1注入了bean2:" + bean2);
            log.warn("bean1依赖注入@Autowired");
        }

        @Resource
        public void resource(Bean2 bean2) {
            log.warn("bean1依赖注入@Resource");
        }

        @Autowired
        public void setHome(@Value("${JAVA_HOME}") String home) {
            log.warn("@Value生效：{}", home);
        }

        @PostConstruct
        public void init() {
            log.warn("bean1初始化");
        }

        @PreDestroy
        public void destroy() {
            log.warn("bean1销毁");
        }
    }

    @Slf4j
    static class Bean2 {
        public Bean2() {
            log.warn("创建了bean2");
        }
    }

    @ConfigurationProperties(prefix = "java")
    @Data
    static class Bean3 {
        private String home;
        private String version;
    }
}
